home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / ScreenSavers / BackSpaceViews / MailWatchView.BackModule / Source / MailWatchView.m < prev    next >
Encoding:
Text File  |  1996-02-04  |  16.8 KB  |  796 lines

  1. //
  2. // MailWatchView.m
  3. //        A BackSpace Module
  4. //        Version 1.1        11/09/94
  5. //        by Robert Lutwak    robert@amo.mit.edu
  6. //
  7. // Revision History
  8. //
  9. // Version 1.1
  10. //
  11. // Replaced calls to opendir() and readdir() with stat() on file name.
  12. // This way we can catch zero-size mail files left behind
  13. // by some mail clients
  14. //
  15. // Added dwrite for no-mail gray level: dwrite MailWatch DarkGray (0.0-1.0)
  16. // 
  17. // Replaced dumb time-counting loop with call to currentTimeInMS
  18. // Added dwrite for when to check (in seconds): dwrite MailWatch TimeToCheck
  19. //
  20. // Obliterated random color change
  21. // Switched to Hue-Saturation-Brightness color method
  22. // Now Hue is scaled 0.0-1.0 proportional amount of mail on 0-100KB
  23. //
  24. // Version 1.2
  25. // 
  26. // Added "magic" names to list for: "time" "day" "date"
  27. // Version 1.3
  28. // Added cool new pref. panel for defaults
  29. // Added "hostname" option
  30. // Added Energy adjustment
  31. // Ya' know, this is just getting to different for minor indices...
  32. //
  33. //
  34. // Version 2.0
  35. //
  36. // Restructuring of pretty much everything.
  37. //
  38. // 2/3/96    Fixed bug in initUsers: which caused an an unitialized user to be
  39. //            created if the NameList was empty
  40. //            Added check for MAXU in addName: to avoid writing beyond bounds
  41. //            of users[].  Now addName: returns -1 if full.
  42. //
  43. // 2/4/96   Fixed assignment of BOOL users[TAG].active in initFrame: so that
  44. //          BOOL is assigned 0 or 1 rather than strcmp("YES", "NO")
  45.  
  46.  
  47. #import "MailWatchView.h"
  48. #import <appkit/appkit.h>
  49. #import <strings.h>
  50. #import <appkit/Font.h>
  51. #import <sys/types.h>
  52. #import <sys/stat.h>
  53. #import <defaults/defaults.h>
  54. #import <math.h>
  55. #import <time.h>
  56. #import <dpsclient/wraps.h>
  57. #import <appkit/FontManager.h>
  58. #include <pwd.h>
  59. #import "Thinker.h"
  60.  
  61. @implementation MailWatchView
  62.  
  63. - checkMail:(int)tag
  64. {
  65.     struct stat fileinfo;
  66.     char path[100];
  67.     int size;
  68.       time_t tTime;
  69.       struct tm *currentTime;
  70.     
  71.     
  72.     if (tag >= NAMETAGSTART) {
  73.                                 // Construct full path
  74.         strcpy(path, MailDirectory);
  75.         strcat(path, "/");
  76.         strcat(path, users[tag].name);
  77.                                     // Get file info check size
  78.         if ( (stat(path, &fileinfo) < 0)
  79.             || ((size=fileinfo.st_size) == 0) ) {
  80.             users[tag].HasMail = NO;
  81.         }
  82.     
  83.         else {
  84.             users[tag].HasMail = YES;
  85.             
  86.             if (BW) {
  87.                 users[tag].hue = 1.0;
  88.             }
  89.             else {
  90.                                 // Change color to indicate amount of Mail 
  91.                 users[tag].hue = (double) size / (double)(MaxMail * 1000);
  92.                 if (users[tag].hue > 1.0) users[tag].hue = 1.0;
  93.             }
  94.         }
  95.     }
  96.                         /* Time */
  97.     else if (tag == TIMETAG) {
  98.           time(&tTime);
  99.           currentTime= localtime(&tTime);
  100.           strftime(users[tag].name, 30, "%H:%M", currentTime);
  101.         
  102.         if (BW) users[tag].hue = 1.0;
  103.         else users[tag].hue = (float) (currentTime->tm_min) / 60.0;
  104.     }
  105.                         /* Day */
  106.     else if (tag == DAYTAG) {
  107.           time(&tTime);
  108.           currentTime= localtime(&tTime);
  109.  
  110.           strftime(users[tag].name, 10, "%A", currentTime);
  111.         if (BW) users[tag].hue = 1.0;
  112.         else users[tag].hue = (float) (currentTime->tm_wday) / 7.0;
  113.  
  114.     }
  115.  
  116.                         /* Date */
  117.     else if (tag == DATETAG) {
  118.           time(&tTime);
  119.           currentTime= localtime(&tTime);
  120.  
  121.           strftime(users[tag].name, 10, "%m/%d", currentTime);
  122.         if (BW) users[tag].hue = 1.0;
  123.         else users[tag].hue = (float) (currentTime->tm_mday) / 31.0;
  124.     }
  125.                             /* Host */
  126.     else if (tag == HOSTTAG) {
  127.          users[tag].hue += (double)Energy/1.e6;    
  128.         if (users[tag].hue > 1.0) users[tag].hue -= 1.0;
  129.     }
  130.  
  131.     users[tag].rect.size.width 
  132.         = [NameFont[(int)users[tag].HasMail] getWidthOf:users[tag].name];      
  133.  
  134.     users[tag].rect.size.height
  135.         = [NameFont[(int)users[tag].HasMail] pointSize];  
  136.         
  137.     users[tag].mass 
  138.         = (float) (users[tag].rect.size.height * users[tag].rect.size.width);                    
  139.  
  140.     return self;
  141. }
  142.  
  143.  
  144. // Elastic collision between two point particles.
  145. // Recoil velocities are calculated by simultaneously solving:
  146. //        m1v1 + m2v2 = m1v1' + m2v2' (momentum conservation)
  147. // and
  148. //         m1 v1^2 + m2 v2^2 = m1 (v1')^2 + m2 (v2')^2 (energy conservation)
  149. //
  150. - collide:(int)i1:(int)i2
  151. {
  152.     float newv1, newv2;
  153.     float m1, m2, v2, v1;
  154.  
  155.  
  156.     m1 = users[i1].mass;
  157.     m2 = users[i2].mass;
  158.  
  159.     v1 = users[i1].v.x;
  160.     v2 = users[i2].v.x;
  161.  
  162.     newv1 = v2 * 2.0 * m2 / (m2 + m1) - v1 * (m2 - m1) / (m2 + m1);
  163.     newv2 =  v2 * (m2 - m1) / (m2 + m1) + v1 * 2.0 * m1 / (m2 + m1);
  164.  
  165.     users[i1].v.x = newv1;
  166.     users[i2].v.x = newv2;
  167.  
  168.     v1 = users[i1].v.y;
  169.     v2 = users[i2].v.y;
  170.  
  171.     newv1 = v2 * 2.0 * m2 / (m2 + m1) - v1 * (m2 - m1) / (m2 + m1);
  172.     newv2 =  v2 * (m2 - m1) / (m2 + m1) + v1 * 2.0 * m1 / (m2 + m1);
  173.  
  174.     users[i1].v.y = newv1;
  175.     users[i2].v.y = newv2;
  176.  
  177.     return self;
  178. }
  179.  
  180.  
  181. - move:(int)u
  182. {
  183.     int i;
  184.  
  185.                                         // Take a step 
  186.     NXOffsetRect(&users[u].rect, users[u].v.x, users[u].v.y);
  187.  
  188.                             // Check for Elastic Collisions
  189.     for (i=0; i < numusers; ++i) {
  190.         if (i == u) continue;
  191.         if (!users[i].active) continue;
  192.         if (NXIntersectsRect(&users[i].rect,&users[u].rect)) {
  193.             NXOffsetRect(&users[u].rect, -1.0*users[u].v.x, -1.0*users[u].v.y);
  194.             [self collide:i:u]; 
  195.             NXOffsetRect(&users[u].rect, users[u].v.x, users[u].v.y);
  196.         }
  197.     }
  198.  
  199.  
  200.                             // Specular reflection from walls
  201.     if ( (users[u].rect.origin.x <= bounds.origin.x) 
  202.         || ((users[u].rect.origin.x+users[u].rect.size.width) >= bounds.size.width) ) {
  203.         NXOffsetRect(&users[u].rect, -2.0*users[u].v.x, 0.0);
  204.            users[u].v.x *= -1.0;
  205.     }
  206.         
  207.       if ( ((users[u].rect.origin.y-users[u].rect.size.height) <= bounds.origin.y)
  208.         || (users[u].rect.origin.y >= bounds.size.height) ) {
  209.         NXOffsetRect(&users[u].rect, 0.0, -2.0 * users[u].v.y);
  210.            users[u].v.y *= -1.0;
  211.     }
  212.  
  213.  
  214.     return self;
  215. }
  216.  
  217. - oneStep
  218. {
  219.     int i;
  220.     BStimeval CurrentTime;
  221.     int checkIt=0;
  222.  
  223.                             // Check for Mail if it's time
  224.     CurrentTime = currentTimeInMs();
  225.     if ((CurrentTime - LastTime) > TimeToCheck) {
  226.         checkIt = 1;
  227.         LastTime = CurrentTime;
  228.     }
  229.  
  230.     for (i=0; i < numusers ; ++i) {
  231.         if (!users[i].active) continue;
  232.  
  233.                                 // Erase last iteration
  234.         [self eraseName:i];
  235.  
  236.          if (checkIt) [self checkMail:i];
  237.         
  238.                             // Move as necessary
  239.         [self move:i]; 
  240.  
  241.         [self drawName:i];
  242.     }
  243.  
  244.     return self;
  245. }
  246.  
  247. - eraseName: (int)u
  248. {
  249.          PSsetgray(0.0);
  250.           PSmoveto(users[u].rect.origin.x,users[u].rect.origin.y);
  251.         
  252.         [NameFont[(int)users[u].HasMail] set];
  253.         PSshow(users[u].name);  
  254.  
  255.         return self;
  256. }
  257.  
  258. - drawName: (int) tag
  259. {
  260.                          // Set Color
  261.           if (users[tag].HasMail) {
  262.             if (BW) PSsetgray(users[tag].hue);
  263.             else PSsethsbcolor(users[tag].hue, 1.0, 1.0);        
  264.         }
  265.  
  266.         else {
  267.             PSsetgray(Gray);
  268.         }
  269.         [NameFont[(int)users[tag].HasMail] set];
  270.  
  271.                             // Draw this iteration
  272.           PSmoveto(users[tag].rect.origin.x,users[tag].rect.origin.y);
  273.         PSshow(users[tag].name);  
  274.         
  275.         return self;
  276. }
  277.  
  278.  
  279. - (const char *)windowTitle
  280. {
  281.   return "MailWatch";
  282. }
  283.  
  284. - drawSelf:(const NXRect *)rects :(int)rectCount
  285. {
  286.     if (!rects || !rectCount) return self;
  287.     PSsetgray(0);
  288.     NXRectFill(rects);
  289.     return self;
  290. }
  291.  
  292. - sizeTo:(NXCoord)width :(NXCoord)height
  293. {
  294.     [super sizeTo:width :height];
  295.     [self initUsers];
  296.     return self;
  297. }
  298.  
  299. - initFrame:(const NXRect *)frameRect
  300. {
  301.     int fontsize;
  302.     static NXDefaultsVector MailWatchDefaults = {
  303.             {"NameList", ""}, 
  304.             {"MailDirectory", "/usr/spool/mail"},
  305.             {"Gray", "0.3"},
  306.             {"MaxMail", "100"},
  307.             {"TimeToCheck", "30"},
  308.             {"NoMailFont", "Times-Roman"},
  309.             {"MailFont", "Times-Italic"},        
  310.             {"NoMailFontSize", "24"},
  311.             {"MailFontSize", "24"},
  312.             {"Time", "YES"},
  313.             {"Date", "YES"},
  314.             {"Day", "YES"},
  315.             {"Host", "YES"},
  316.             {"Energy", "10000"},
  317.             {NULL} };
  318.  
  319.  
  320.     [super initFrame:frameRect];
  321.     [self allocateGState];        // For faster lock/unlockFocus
  322.  
  323. //    Load Defaults:
  324.  
  325.     NXRegisterDefaults("MailWatch", MailWatchDefaults);
  326.  
  327.     strncpy(NameList, NXGetDefaultValue("MailWatch", "NameList"), 1000);
  328.  
  329.     users[TIMETAG].active 
  330.         = (strcmp(NXGetDefaultValue("MailWatch","Time"),"YES") == 0);
  331.     users[DAYTAG].active 
  332.         = (strcmp(NXGetDefaultValue("MailWatch","Day"),"YES") == 0);
  333.     users[DATETAG].active 
  334.         = (strcmp(NXGetDefaultValue("MailWatch","Date"),"YES") == 0);
  335.     users[HOSTTAG].active 
  336.         = (strcmp(NXGetDefaultValue("MailWatch","Host"),"YES") == 0);
  337.  
  338.  
  339.     strncpy(MailDirectory, NXGetDefaultValue("MailWatch", "MailDirectory"), 100);
  340.  
  341.     Gray = atof(NXGetDefaultValue("MailWatch","Gray"));
  342.     MaxMail = atoi(NXGetDefaultValue("MailWatch","MaxMail"));
  343.  
  344.     fontsize = atoi(NXGetDefaultValue("MailWatch", "MailFontSize"));
  345.       NameFont[YESMAIL] 
  346.         = [Font newFont:NXGetDefaultValue("MailWatch", "MailFont") 
  347.         size:fontsize];
  348.  
  349.     fontsize = atoi(NXGetDefaultValue("MailWatch", "NoMailFontSize"));
  350.       NameFont[NOMAIL]
  351.          = [Font newFont:NXGetDefaultValue("MailWatch", "NoMailFont") 
  352.         size:fontsize];    
  353.     
  354.     Energy = atoi(NXGetDefaultValue("MailWatch", "Energy"));
  355.     
  356.     TimeToCheck = 1000 * atoi(NXGetDefaultValue("MailWatch","TimeToCheck"));
  357.     LastTime = 0;
  358.  
  359. //    
  360.       [self setFlipped:YES];
  361.  
  362.     [inspectorPanel display];
  363.  
  364. // Determine whether to use color or BW
  365.     if ([Window defaultDepthLimit] == NX_TwoBitGrayDepth) BW = 1;
  366.     
  367.  
  368.     return self;
  369. }
  370.  
  371.  
  372. - initUsers
  373. {
  374.     char *pn, *un, name[30];
  375.     BOOL done;
  376.     int tag;
  377.     
  378.     numusers = 0;
  379.     for (tag=0; tag < NAMETAGSTART; ++tag) {
  380.         sprintf(name, "tag%d", tag);
  381.         tag = [self addName:name];
  382.     }
  383.  
  384.     pn = NameList;
  385.     done = NO;
  386.     while (!done) {
  387.         while (*pn == ' ') ++pn;
  388.         un = name;
  389.         while(*pn != ' ') {
  390.             if (*pn == 0) {
  391.                 done = YES;
  392.                 break;
  393.             }
  394.             *un++ = *pn++;
  395.         }
  396.         *un = 0;
  397.         if (*name != 0)    {
  398.             tag = [self addName:name];
  399.             if (tag < 0) return self;
  400.             users[tag].active = YES;
  401.         }
  402.     }    
  403.     
  404.     return self;
  405. }
  406.  
  407.  
  408. //- (BOOL) useBufferedWindow{    return YES;}
  409.  
  410. - inspector:sender
  411. {
  412.     char buf[500];
  413.     int tag;
  414.  
  415.  
  416.  
  417.     if (!inspectorPanel) {
  418.                             // Load NIB
  419.         [NXBundle 
  420.             getPath:buf 
  421.             forResource:"MailWatchView" 
  422.             ofType:"nib" 
  423.             inDirectory:[(BSThinker()) moduleDirectory:"MailWatch"]
  424.             withVersion:0
  425.         ];
  426.  
  427.         [NXApp 
  428.             loadNibFile:buf 
  429.             owner:self 
  430.             withNames:NO
  431.         ];
  432.  
  433.                             // Load Help
  434.         if (helpPanel == nil) helpPanel = [NXHelpPanel new];    
  435.         sprintf(buf, "%s/English.lproj",
  436.             [(BSThinker()) moduleDirectory:"MailWatch"]);
  437.         [helpPanel addSupplement:"Help" inPath:buf];
  438.                 
  439.                 
  440.         // Initialization
  441.                             // Settings Panel
  442.                             // Energy
  443.         [EnergySlider setIntValue:(int)sqrt((double)Energy)];
  444.                             // Checking for Mail
  445.         [MailDirectoryText setStringValue:MailDirectory];
  446.         [TimeToCheckSlider setIntValue:(TimeToCheck/1000)];
  447.         [TimeToCheckText setIntValue:(TimeToCheck/1000)];
  448.                             // Colors
  449.         [GraySlider setFloatValue:Gray];
  450.         sprintf(buf, "%3.1f", Gray);
  451.         [GrayText setStringValue:buf];
  452.         [MaxMailSlider setIntValue:MaxMail];
  453.         [MaxMailText setIntValue:MaxMail];
  454.         
  455.                             // NameList
  456.                             // NameBrowser
  457.         [NameBrowser setDelegate:self];
  458.         [NameBrowser setDoubleAction:@selector(browserChanged:)];
  459.         [NameBrowser setTarget:self];
  460.                             // NameButtons
  461.         for (tag=0; tag < NAMETAGSTART; ++tag) {
  462.             [[NameButtons findCellWithTag:tag] setState:users[tag].active];
  463.         }
  464.  
  465.     }
  466.  
  467.     return inspectorPanel;
  468. }
  469.  
  470.  
  471. - setEnergy:sender
  472. {
  473.     char buf[10];
  474.     int i;
  475.     double Eold;
  476.     double factor;
  477.     
  478.     Eold = Energy;
  479.     Energy = [sender intValue] * [sender intValue];
  480.  
  481.     sprintf(buf, "%d", Energy);
  482.     NXWriteDefault("MailWatch", "Energy", buf);
  483.  
  484.     factor = sqrt(Energy/Eold);
  485.     
  486.     for (i=0; i < numusers; ++i) {
  487.         users[i].v.x *= factor;
  488.         users[i].v.y *= factor;
  489.     }
  490.     return self;
  491. }
  492.  
  493. - setTimeToCheck:sender
  494. {
  495.     char buf[10];
  496.     int Secs;
  497.     
  498.     Secs = [sender intValue];
  499.     sprintf(buf, "%d", Secs);
  500.     NXWriteDefault("MailWatch", "TimeToCheck", buf);
  501.     [TimeToCheckSlider setIntValue:Secs];
  502.     [TimeToCheckText setIntValue:Secs];
  503.  
  504.     TimeToCheck = Secs * 1000;      /* in milliseconds */
  505.  
  506.     return self;
  507. }
  508.  
  509. - clearNames
  510. {
  511.     int i;
  512.     id myView;
  513.     
  514.     [self lockFocus];
  515.     myView = [(BSThinker()) backView];
  516.     for (i=0; i < numusers; ++i) [myView eraseName:i];
  517.     [self unlockFocus];
  518.     
  519.     return self;
  520. }
  521.  
  522.  
  523. - NameButtonsChanged:sender
  524. {
  525.     id selectedButton;
  526.     int tag;
  527.     BOOL State;
  528.     
  529.     selectedButton = [sender selectedCell];
  530.     State = [selectedButton state];
  531.     tag = [selectedButton tag];
  532.     
  533.     users[tag].active = State;
  534.  
  535.     NXWriteDefault("MailWatch", [selectedButton title], State ? "YES" : "NO");    
  536.  
  537.     [self clearNames];
  538.  
  539.     return self;
  540. }
  541.  
  542. - browserChanged:sender
  543. {
  544.     id cell;
  545.     char title[20];
  546.     int tag;
  547.     
  548.     cell = [sender  selectedCell];
  549.     strcpy(title, [cell stringValue]);
  550.         
  551.     tag = [self addName:title];
  552.     
  553.     if (tag < 0) return self;
  554.     
  555.     if (users[tag].active) {
  556.         users[tag].active = NO;
  557.         [cell setImage:[[NXImage findImageNamed:"CheckOff"] copy]];
  558.     }
  559.     else {
  560.         users[tag].active = YES;
  561.         [cell setImage:[[NXImage findImageNamed:"CheckOn"] copy]];
  562.     }
  563.  
  564.     [sender displayAllColumns];
  565.     
  566.     *NameList = 0;
  567.     for (tag=NAMETAGSTART; tag < numusers; ++tag)
  568.         if (users[tag].active)
  569.             sprintf(NameList, "%s %s", NameList, users[tag].name);
  570.     NXWriteDefault("MailWatch", "NameList", NameList);
  571.     
  572.                         // Don't leave shadows 
  573.     [self clearNames];
  574.  
  575.     return self;
  576. }
  577.  
  578.  
  579. - setMailDirectory:sender
  580. {    
  581.     strncpy(MailDirectory, [sender stringValue], 100);
  582.     NXWriteDefault("MailWatch", "MailDirectory", MailDirectory);
  583.     return self;
  584. }
  585.  
  586. -(int)browser:sender fillMatrix:(id)matrix inColumn:(int)col
  587. {
  588.     struct passwd *pwentry;
  589.     int row;
  590.     id newCell;
  591.     int tag;
  592.  
  593.     if (!CheckOn || !CheckOff) [self initImages];
  594.     
  595.     setpwent();
  596.     for (row=0; (pwentry = getpwent()) != NULL;) {
  597.         if (!strcmp(pwentry->pw_name, "uucp")) continue;
  598.         if (!strcmp(pwentry->pw_name, "nobody")) continue;
  599.         if (!strcmp(pwentry->pw_name, "agent")) continue;
  600.         if (!strcmp(pwentry->pw_name, "daemon")) continue;
  601.         if (!strcmp(pwentry->pw_name, "sybase")) continue;
  602.         
  603.         [matrix addRow];
  604.  
  605.         newCell = [matrix cellAt:row:col];
  606.         
  607.         [newCell initTextCell:pwentry->pw_name];
  608.         [newCell setLoaded:YES];
  609.         [newCell setLeaf:YES];
  610.         
  611.         for (tag=NAMETAGSTART; tag < numusers; ++tag) {
  612.             if (!strcmp(users[tag].name, pwentry->pw_name)) break;
  613.         }
  614.         if (tag != numusers) 
  615.             [newCell setImage:[[NXImage findImageNamed:"CheckOn"] copy]];
  616.         else 
  617.             [newCell setImage:[[NXImage findImageNamed:"CheckOff"] copy]];
  618.         ++row;
  619.     }
  620.     endpwent();
  621.     
  622.  
  623.     return(row);
  624. }
  625.  
  626. - initImages
  627. {
  628.     CheckOn = [NXImage findImageNamed:"CheckOn"];
  629.     CheckOff = [NXImage findImageNamed:"CheckOff"];
  630.     return self;
  631.  
  632.     return self;
  633. }
  634.  
  635.                                 // Returns tag of name
  636.                                 // Creating new entry if necessary
  637. - (int)addName:(char *)newName
  638. {
  639.     BOOL bad;
  640.     int j;
  641.     double v, vx, vy;
  642.     int tag;
  643.     
  644.                     // Check to see if it already exists
  645.     for (tag=0; tag < numusers; ++tag) {
  646.         if (!strcmp(users[tag].name, newName)) return tag;
  647.     }
  648.     
  649.                     // Check to make sure we've got room
  650.     if (numusers >= MAXU) return(-1);
  651.         
  652.                     // Gotta create it
  653. //    fprintf(stderr, "Creating Name %s\n", newName);
  654.     strcpy(users[tag].name, newName);
  655.     
  656.     if (tag < NAMETAGSTART) {
  657.         users[tag].HasMail = YES;
  658.         if (tag == HOSTTAG) gethostname(users[HOSTTAG].name, NAMELEN);
  659.     }
  660.     else {
  661.         users[tag].active = NO;
  662.     }
  663.  
  664.     [self checkMail:tag];
  665.  
  666. //    Find an unoccupied place to put it:
  667.     bad = YES;
  668.     while (bad) {
  669.         users[tag].rect.origin.x = 
  670.             randBetween(bounds.origin.x, 
  671.             bounds.size.width-users[tag].rect.size.width);
  672.         users[tag].rect.origin.y = 
  673.             randBetween(bounds.origin.y+users[tag].rect.size.height, 
  674.             bounds.size.height-users[tag].rect.size.height);
  675.  
  676.         for (bad=NO,j=tag-1; j >= 0; --j) {
  677.             if (NXIntersectsRect(&users[j].rect, &users[tag].rect))
  678.             bad = YES;
  679.         }                            
  680.     }
  681.             
  682.     v = sqrt(2 * Energy / users[tag].mass);
  683.  
  684.      vx = randBetween(0, v);
  685.       vy = sqrt (v*v - vx * vx);
  686.  
  687.     users[tag].v.x = vx;
  688.     users[tag].v.y = vy;    
  689.     
  690.     ++numusers;
  691.     
  692.     return tag;
  693.  
  694. }
  695.  
  696. - inspectorWillBeRemoved
  697. {
  698.     if (SettingsPanel) [SettingsPanel orderOut:self];
  699.     if (NameListInspector) [NameListInspector orderOut:self];
  700.     if (InfoPanel) [InfoPanel orderOut:self];
  701.     if (fontPanel) [fontPanel orderOut:self];
  702.     if (helpPanel) [helpPanel orderOut:self];
  703.  
  704.     return self;
  705. }
  706.  
  707. - helpPushed:sender
  708. {
  709.     char HelpPath[MAXPATHLEN];
  710.  
  711.     [helpPanel makeKeyAndOrderFront:self];
  712.     
  713.     sprintf(HelpPath, "%s/English.lproj/Help/Overview.rtfd", 
  714.         [(BSThinker()) moduleDirectory:"MailWatch"]);
  715.     [helpPanel showFile:HelpPath atMarker:NULL];
  716.     
  717.     return self;
  718. }
  719.  
  720. - fontPushed:sender
  721. {    
  722.     if (fontManager == nil) fontManager = [FontManager new];
  723.     
  724.     [fontManager setSelFont:NameFont[(int)settingMailFont] isMultiple:NO];
  725.  
  726.     if (fontPanel == nil) {
  727.         fontPanel = [fontManager getFontPanel:YES];
  728.         [fontPanel setAccessoryView:fontPopUpView];
  729.     }
  730.  
  731.     [fontPanel setDelegate:self];
  732.     [fontPanel makeKeyAndOrderFront:self];
  733.     return self;
  734. }
  735.  
  736. - changeFont:sender
  737. {
  738.     char buf1[20], buf2[20];
  739.  
  740.  
  741.     [self clearNames];
  742.     NameFont[(int)settingMailFont] 
  743.         = [fontManager convertFont:NameFont[(int)settingMailFont]];
  744.  
  745.                             /* Either "MailFont" or "NoMailFont" */
  746.     strcpy(buf1, [[fontPopUp findCellWithTag:(int)settingMailFont] title]);
  747.     NXWriteDefault("MailWatch", buf1, [NameFont[(int)settingMailFont] name]);
  748.  
  749.                             /* Make that "MailFontSize" or "NoMailFontSize" */
  750.     strcat(buf1, "Size");
  751.     sprintf(buf2, "%g", [NameFont[(int)settingMailFont] pointSize]);
  752.     NXWriteDefault("MailWatch", buf1, buf2);        
  753.  
  754.  
  755.     return self;
  756. }
  757.  
  758. - fontPopUpChanged:sender
  759. {
  760.     settingMailFont = [[sender selectedCell] tag];
  761.     [fontManager setSelFont:NameFont[(int)settingMailFont] isMultiple:NO];
  762.  
  763.     return self;
  764. }
  765.  
  766. - setGray:sender
  767. {
  768.     char buf[10];
  769.     
  770.     Gray = [sender floatValue];
  771.     
  772.     sprintf(buf, "%3.1f", Gray);
  773.     
  774.     [GrayText setStringValue:buf];
  775.     
  776.     NXWriteDefault("MailWatch", "Gray", buf);
  777.  
  778.     return self;
  779.  
  780. }
  781.  
  782. - setMaxMail:sender
  783. {
  784.     char buf[30];
  785.     
  786.     MaxMail = [sender intValue];
  787.     
  788.     [MaxMailText setIntValue:MaxMail];
  789.     sprintf(buf, "%d", MaxMail);
  790.     NXWriteDefault("MailWatch", "MaxMail", buf);
  791.  
  792.     return self;
  793. }
  794.  
  795. @end
  796.